package com.duobaoyu.dby.supply.biz.client.resource.impl;

import com.duobaoyu.dby.channel.adapter.bean.logistics.LogisticsTrackInfo;
import com.duobaoyu.dby.common.core.constant.CommonConstants;
import com.duobaoyu.dby.common.core.constant.SecurityConstants;
import com.duobaoyu.dby.common.core.constant.ServiceNameConstants;
import com.duobaoyu.dby.common.core.util.R;
import com.duobaoyu.dby.resource.api.feign.*;
import com.duobaoyu.dby.resource.common.api.dto.config.ExceptionMappingDTO;
import com.duobaoyu.dby.resource.common.api.dto.config.StateDTO;
import com.duobaoyu.dby.resource.common.api.dto.logistics.LogisticsNumberDTO;
import com.duobaoyu.dby.resource.common.api.to.config.*;
import com.duobaoyu.dby.resource.common.api.to.logistics.LogisticsNumberTO;
import com.duobaoyu.dby.resource.remote.common.dto.area.AddressInfoDTO;
import com.duobaoyu.dby.resource.remote.common.enums.ResourceCodeEnum;
import com.duobaoyu.dby.resource.remote.common.enums.ResourceTypeEnum;
import com.duobaoyu.dby.resource.remote.common.enums.RiskStrategyEnum;
import com.duobaoyu.dby.resource.remote.common.json.PlatformServiceMappingInfoJson;
import com.duobaoyu.dby.resource.remote.common.json.RiskStrategyContent;
import com.duobaoyu.dby.resource.remote.common.to.area.AddressInfoTO;
import com.duobaoyu.dby.resource.remote.common.to.config.ChannelConfigTO;
import com.duobaoyu.dby.resource.remote.common.to.config.*;
import com.duobaoyu.dby.resource.remote.common.to.logistics.ExpressInfoTO;
import com.duobaoyu.dby.supply.biz.client.resource.ResourceApiClient;
import com.duobaoyu.dby.supply.biz.client.resource.bean.bo.*;
import com.duobaoyu.dby.supply.biz.client.resource.bean.dto.AreaCityInfoDTO;
import com.duobaoyu.dby.supply.biz.client.resource.bean.dto.AreaInfoDTO;
import com.duobaoyu.dby.supply.biz.client.resource.bean.dto.ChannelRuleDTO;
import com.duobaoyu.dby.supply.biz.client.resource.bean.dto.StateInfoDTO;
import com.duobaoyu.dby.supply.biz.client.resource.converter.ResourceConverter;
import com.duobaoyu.dby.supply.biz.enums.LocalCacheKeys;
import com.duobaoyu.dby.supply.biz.exception.SupplyChainBizException;
import com.duobaoyu.dby.supply.biz.util.RemoteResultCheckUtil;
import com.duobaoyu.dby.supply.core.cache.service.LocalCacheService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liyang
 * @version 1.0.0
 * @ClassName ResourceServiceImpl
 * @createTime 10:37:00 2023/09/26
 */
@Component
@RequiredArgsConstructor
public class ResourceApiClientImpl implements ResourceApiClient {

    private final LocalCacheService<String,BusinessConfigBO> localCacheService;
    private final ResourceConverter resourceConverter;
    private final RemoteResourceAddressService remoteResourceAddressService;
    private final RemoteResourceLogisticsService remoteResourceLogisticsService;
    private final RemoteResourceBizConfigService remoteResourceBizConfigService;
    private final RemoteResourceDictionaryService remoteResourceDictionaryService;
    private final RemoteResourceStateMappingService remoteResourceStateMappingService;
    private final RemoteResourceChannelConfigService remoteResourceChannelConfigService;
    private final RemoteResourceAfterSaleReasonService remoteResourceAfterSaleReasonService;
    private final RemoteResourceChannelSettingApiService remoteResourceChannelSettingApiService;
    private final RemoteResourceChannelRuleConfigService remoteResourceChannelRuleConfigService;
    private final RemoteResourceRiskStrategyConfigService remoteResourceRiskStrategyConfigService;


    @Override
    public AfterSaleSettingConfigBO queryAfterSaleSettingConfig(String channelCode) {
        R<AfterSaleSettingConfigTO> result = remoteResourceChannelSettingApiService.afterSaleSettingConfig(channelCode, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, channelCode);
        AfterSaleSettingConfigTO data = result.getData();
        return Optional.ofNullable(data).map(resourceConverter::toAfterSaleSettingConfig).orElse(null);
    }

    @Override
    public AuditStrategyConfigBO queryAuditStrategyConfig(String channelCode) {
        R<AuditStrategyConfigTO> result = remoteResourceChannelSettingApiService.auditStrategyConfig(channelCode, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, channelCode);
        return Optional.ofNullable(result.getData()).map(resourceConverter::toAuditStrategyConfig).orElse(null);
    }

    @Override
    public OrderRuleConfigBO queryOrderRuleConfig(String channelCode) {
        R<OrderRuleConfigTO> result = remoteResourceChannelSettingApiService.orderRuleConfig(channelCode, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, channelCode);
        return Optional.ofNullable(result.getData()).map(resourceConverter::toOrderRuleConfig).orElse(null);
    }

    @Override
    public PrefreightConfigBO queryPrefreightConfig(String channelCode) {
        R<PrefreightConfigTO> result = remoteResourceChannelSettingApiService.prefreightConfig(channelCode, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, channelCode);
        return Optional.ofNullable(result.getData()).map(resourceConverter::toPrefreightConfig).orElse(null);
    }

    /**
     * 根据售后类型获取售后原因
     *
     * @param afterSaleTypes
     * @return
     */
    @Override
    public List<AfterSaleReasonBO> queryAfterSaleReasons(List<Integer> afterSaleTypes) {
        Map<Integer, List<AfterSaleReasonBO>> resultMap = this.queryAfterSaleReason(afterSaleTypes);
        return resultMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
    }

    @Override
    public Map<Integer, List<AfterSaleReasonBO>> queryAfterSaleReason(List<Integer> afterSaleTypes) {
        R<Map<Integer, List<AfterSaleReasonTO>>> result = remoteResourceAfterSaleReasonService.getAfterSaleReasonCacheByAfterSaleTypes(afterSaleTypes, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, afterSaleTypes);
        Map<Integer,List<AfterSaleReasonBO>> resultMap = Maps.newHashMap();
        result.getData().forEach((k,v) -> resultMap.put(k,resourceConverter.toAfterSaleReasonList(v)));
        return resultMap;
    }

    @Override
    public AreaInfoBO getChannelAddress(AreaInfoDTO areaInfo) {
        AddressInfoDTO dto = resourceConverter.toAddress(areaInfo);
        R<AddressInfoTO> result = remoteResourceAddressService.getChannelRuleAddress(dto, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, areaInfo);
        return resourceConverter.toAddress(result.getData());
    }

    @Override
    public AreaCityInfoBO getChannelCityAddress(AreaCityInfoDTO areaCityInfo) {
        AddressInfoDTO dto = resourceConverter.toAddressCity(areaCityInfo);
        R<AddressInfoTO> result = remoteResourceAddressService.getChannelCityAddress(dto, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, areaCityInfo);
        return resourceConverter.toAddressCity(result.getData());
    }

    @Override
    public void addressBindSimilarity(String channelCode, Integer similarity) {
        R result = remoteResourceAddressService.addressBindSimilarity(channelCode, similarity, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, channelCode,similarity);
    }


    @Override
    public ChannelConfigBO channelConfig(String channelCode) {
        R<ChannelConfigTO> result = remoteResourceChannelConfigService.channelConfigDetailByChannelCode(channelCode, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, channelCode);
        return resourceConverter.toChannelConfig(result.getData());
    }

    @Override
    public ChannelRuleBO toLocalExceptionRule(ChannelRuleDTO channelRule) {
        ExceptionMappingDTO dto = resourceConverter.toChannelExceptionRule(channelRule);
        R<ExceptionMappingTO> result = remoteResourceChannelRuleConfigService.toLocalExceptionCodeMapping(dto, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, channelRule);
        return resourceConverter.toChannelExceptionRule(result.getData());
    }

    @Override
    public List<DictionaryConfigBO> dictionaryByCode(String dictionaryCode) {
        R<List<DictionaryConfigTO>> result = remoteResourceDictionaryService.getDictionaryByCode(dictionaryCode, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, dictionaryCode);
        return resourceConverter.toDictionaryConfigs(result.getData());
    }

    @Override
    public StateInfoBO getStateInfo(StateInfoDTO stateInfo) {
        StateDTO dto = resourceConverter.toStateInfo(stateInfo);
        R<StateTO> result = remoteResourceStateMappingService.getStateInfo(dto, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, stateInfo);
        return resourceConverter.toStateInfo(result.getData());
    }

    @Override
    public List<MappingBO> getState(String stateCode, String label, Boolean ifDeprecated) {
        R<List<MappingTO>> result = remoteResourceStateMappingService.getState(stateCode, label, ifDeprecated, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, stateCode,label,ifDeprecated);
        return resourceConverter.toMapping(result.getData());
    }

    @Override
    public BusinessConfigBO getBizCodeInfo(String bizCode) {
        String localCacheKey = LocalCacheKeys.BIZ_CODE.formatKey(bizCode);
        BusinessConfigBO cache = localCacheService.getCache(localCacheKey);
        if (Objects.isNull(cache)) {
            synchronized (this) {
                cache = localCacheService.getCache(localCacheKey);
                if (Objects.isNull(cache)) {
                    cache = this.getCacheBizCode(bizCode);
                    if (Objects.nonNull(cache)) {
                        localCacheService.putCache(localCacheKey, cache);
                    }
                }
            }
        }
        return cache;
    }

    @Override
    public Map<String, ExpressInfoBO> getExpressInfoAllCacheByChannelCode(String channelCode) {
        R<Map<String, ExpressInfoTO>> result = remoteResourceLogisticsService.getExpressInfo(channelCode, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, channelCode);
        Map<String, ExpressInfoBO> resultMap = Maps.newHashMap();
        if (MapUtils.isNotEmpty(result.getData())) {
            result.getData().forEach((k, v) -> resultMap.put(k, resourceConverter.toExpressInfo(v)));
        }
        return resultMap;
    }

	@Override
	public LogisticsTrackInfo getLogisticsTrack(String logisticsNo, String expressCompanyCode, String phone) {
		LogisticsNumberDTO logisticsNumberDTO = new LogisticsNumberDTO();
		logisticsNumberDTO.setLogisticsNo(logisticsNo);
		logisticsNumberDTO.setResourceCode(ResourceCodeEnum.FEGINE.getValue());
		logisticsNumberDTO.setResourceType(ResourceTypeEnum.EXPRESS_LOGISTICS.getResourceType());
		logisticsNumberDTO.setExpressCompanyCode(expressCompanyCode);
		logisticsNumberDTO.setPhoneNo(phone);
		R<LogisticsNumberTO> result = remoteResourceLogisticsService.logisticsNoQuery(logisticsNumberDTO, SecurityConstants.FROM_IN);
		RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, logisticsNo,expressCompanyCode,phone);
		return resourceConverter.toLogisticsTrackDto(result.getData());
	}

    @Override
    public Boolean largeOrderCheck(BigDecimal orderAmount) {
        R<RiskStrategyConfigTO> strategy = remoteResourceRiskStrategyConfigService.strategy(RiskStrategyEnum.LARGE_ORDER.getValue(), SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(strategy, ServiceNameConstants.RESOURCE_SERVICE, RiskStrategyEnum.LARGE_ORDER.getValue());
        //大额订单预警金额
        Integer orderAccount = strategy.getData().getContent().stream().findFirst().map(RiskStrategyContent::getOrderAccount)
                .orElseThrow(() -> new SupplyChainBizException("资源服务数据异常"));
        return BigDecimal.valueOf(orderAccount).compareTo(orderAmount) < CommonConstants.ZERO;
    }

    private BusinessConfigBO getCacheBizCode(String bizCode) {
        R<BizConfigTO> result = remoteResourceBizConfigService.getBizCode(bizCode, SecurityConstants.FROM_IN);
        RemoteResultCheckUtil.checkRemoteResult(result, ServiceNameConstants.RESOURCE_SERVICE, bizCode);
        BizConfigTO to = result.getData();
        List<Long> platformServiceIds = Lists.newArrayList();
        if (Objects.nonNull(to) && CollectionUtils.isNotEmpty(to.getPlatformServiceMappingInfo())) {
            platformServiceIds = to.getPlatformServiceMappingInfo().stream().map(PlatformServiceMappingInfoJson::getPlatformServiceId).collect(Collectors.toList());
        }
        return BusinessConfigBO.builder().bizCode(to.getBizCode()).bizDescribe(to.getBizDescribe())
                .bizCustom(to.getBizCustom()).saasProductMapping(to.getSaasProductMapping()).orderSnPrefix(to.getOrderSnPrefix())
                .platformServiceIds(platformServiceIds).build();
    }
}
